/* Copyright 2018 Tronlong Elec. Tech. Co. Ltd. All Rights Reserved. */

#include <stdio.h>
#include <stdbool.h>
#include <libgen.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/select.h>
#include <linux/input.h>

#include <pthread.h>
#include <poll.h>
#include "myLog.h"
#include "gpio.h"
#include "irq.h"
#include "main.h"


#define INADEQUATE_CONDITIONS 3

typedef enum { KEY_CODE_NONE = 0, KEY_CODE_USER0,KEY_FPGA } KeyCode;

static int fpgaFd = 0;
bool intcFlag = false;
static int fpgaGpio = 0;
static char *dev = "/dev/input/event5";
static int gpioDev = 226;

static int checkButtonPressed(int fd) {
    assert(fd >= 0);

    /* wait button being pressed or released. */
    fd_set input;
    FD_ZERO(&input);
    FD_SET(fd, &input);
    int ret = select(fd + 1, &input, NULL, NULL, NULL);
    if (ret < 0) {
        printf("%s", strerror(errno));
        return -1;
    }

    /* read event */
    struct input_event buf;
    if (read(fd, &buf, sizeof(struct input_event)) < 0) {
        printf("%s", strerror(errno));
        return -1;
    }

    /* Check the input_event value */
    switch (buf.code) {
    case KEY_PROG3:
        /* 1: pressed; 0: released */
        if (buf.value == 1)
            return KEY_CODE_USER0;
        break;
    case KEY_0:
        if (buf.value == 1)
            return KEY_FPGA;
        break;
    default:
        return KEY_CODE_NONE;
        break;
    }

    return KEY_CODE_NONE;
}

/**
 * @description: 中断模式下的触发线程
 * @param {void *} argc
 * @return {void *} 
 */
void *trigger(void *argc)
{
    double timeout = 0;
	int64_t g_iclock = 0;
    int key_code  = 0;
    while (intcFlag) {
        key_code = checkButtonPressed(fpgaFd);
        if (key_code < 0)
            continue;

        switch (key_code) {
            case KEY_CODE_USER0:
                qlog_i("Key key5 pressed!");
                break;
            case KEY_FPGA:
                qlog_i("intc fpga triggered = 1 !");
                setGpioValue(fpgaGpio,1);
                timeout = (double)((time_now()-g_iclock)/1000);
                qlog_i("clock=%0.3fms",(timeout/1000));
                g_iclock = time_now();
                setGpioValue(fpgaGpio,0);
            default:
                break;
        }
    }
    close(fpgaFd);
}

/**
 * @description: 轮询模式下的触发线程
 * @param {void *} argc
 * @return {void *} 
 */
void *uPoll(void *argc)
{   
    double timeout = 0;
	int64_t g_iclock = 0;
    char buffer[16];
    int len;
    struct pollfd fds[1];
    fds[0].fd=fpgaFd;
    fds[0].events=POLLPRI;
    while(intcFlag)
    {
        if(poll(fds,1,0)==-1)
        {
            perror("poll failed!\n");
            break;
        }
        if(fds[0].revents&POLLPRI)
        {
            if(lseek(fpgaFd,0,SEEK_SET)==-1)
            {
                perror("lseek failed!\n");
                break;
            }
            
            if((len=read(fpgaFd,buffer,sizeof(buffer)))==-1)
            {
                perror("read failed!\n");
                break;
            }
            buffer[len]=0;
            if(buffer[0] = "1")
            {
                qlog_i("fpga triggered = 1 !");
                setGpioValue(fpgaGpio,1);
                timeout = (double)((time_now()-g_iclock)/1000);
                qlog_i("clock=%0.3fms",(timeout/1000));
                g_iclock = time_now();
                setGpioValue(fpgaGpio,0);
            } else {
                qlog_i("%s",buffer);
            }
            memset(buffer,0,sizeof(buffer));

        }
    }
}



int fpgaIntc(int ngpio) 
{
    int ret = 0;
    // char *dev = NULL;
    
    pthread_t tid1;
    fpgaGpio = ngpio;
    fpgaFd = open(dev, O_RDONLY);
    if (fpgaFd < 0) {
        qlog_e("Error: Failed to open device\n");
        return INADEQUATE_CONDITIONS;
    }
    qlog_i("Please press the key5 to test.\n");
    intcFlag = true;
    gpioExport(fpgaGpio,"out",4);
    ret = pthread_create(&tid1,NULL,trigger,NULL);//创建线程
   
    return ret;
}

int fgpaPoll(int ngpio)
{
    int ret = 0;
     char path[50];

    pthread_t tid1;
    fpgaGpio = ngpio;
    gpioExport(gpioDev,"in",3);//导出需要检测的GPIO
    setGpioEdge(gpioDev);//设置触发
    memset(path,0,sizeof(path));
    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", gpioDev); 
    fpgaFd=open(path,O_RDONLY);
    if(fpgaFd<0)
    {
        qlog_e("open %s failed! ", path);  
        return;
    }
    gpioExport(fpgaGpio,"out",4);
    intcFlag = true;
    ret = pthread_create(&tid1,NULL,uPoll,NULL);//创建线程
}
